import time

from MusicPlayMainWindow import UiMainWindow  # 主窗口程序
import pygame
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMessageBox, QFileDialog  # 弹窗消息
import sys
import os
from mutagen.mp3 import MP3
from mutagen.oggvorbis import OggVorbis
from PyQt5.QtCore import QTimer
from mutagen.flac import FLAC

window = QtWidgets.QApplication(sys.argv)  # 实例化应用对象
main_windows = QtWidgets.QMainWindow()
# 需要替换的字符串的人为定义
music_now_play_list = []  # 正在播放的音乐文件名列表
songs_list = []  # 文件夹内的音乐列表
songs_list_just_name = []  # 文件夹内的音乐列表名字
songs_list_just_name_show_list = []  # 展示框内的文字
flag_sound_pushbutton = 0  # 0表示静音，1表示有声音
songs_play_last_state = ""  # 上一次退出程序时，播放器播放的音乐
songs_play_now_state = ""  # 当前程序播放的音乐
voice_level_begin = 0  # 程序开始时的音量
voice_level_move = voice_level_begin  # 程序运行时,滑条改变的动态音量
songs_last_index = 0  # 上一次退出程序时，播放器播放的音乐的下标
songs_play_index = songs_last_index  # 程序运行中，音乐正在播放的下标
songs_play_list_index = 0  # 展示框内的音乐下标
flag_voice_level_changed = 0  # 判断程序是否是刚开始运行
lrc_list = []  # lrc歌词文件名列表
lrc_list_contain = {}  # 存储歌词内容的字典
songs_now_length = 0  # 当前音乐处于的进度
songs_sum_length = 0  # 音乐的总长度
flag_music_change = 0  # 音乐是否切换的标志，0表示没有切换，1表示切换了
position_music_play = 0.0  # 当前音乐播放的位置
flag_exe_begin = 0
exchange_quiet_to_noisy = 0  # 0表示静音，1表示有声音（初始为静音）
songs_play_order = -1  # -1表示单曲循环，1表示列表循环（初始为列表循环）
songs_user_select_path = ""  # 用户自选的歌曲路径
music_lrc_dict = {}  # 歌词字典
music_lrc_list = []  # 歌词列表，每个元素为一个二维列表，这个二维列表的第一个元素为时间，第二个元素为歌词
searched_song_default = []  # 用户觉得不对的歌曲名
song_lrc_show_index = 0  # 歌词展示的下标
nums_songs_last_page = 0  # 最后一页剩下的歌曲数目


# 界面以及部分槽函数的定义
class MainUIAndSlot(QtWidgets.QMainWindow, UiMainWindow, QFileDialog):
    # 初始化
    def __init__(self, parent=None):
        super(MainUIAndSlot, self).__init__(parent)
        self.setup_main_ui(main_windows)
        self.FileName = ""
        self.setup()

    # 文件弹窗
    def get_file(self):
        global songs_list, songs_list_just_name, songs_list_just_name_show_list, nums_songs_last_page
        filename, _ = QFileDialog.getOpenFileNames(self, "音乐", "./", "music(*.mp3 *.ogg *flac)")
        if filename:
            self.FileName = filename[0]
            songs_list.append(self.FileName)
            tmp = self.FileName.split("/")
            file_name = tmp[len(tmp) - 1].split(".")[0]
            songs_list_just_name.append(file_name)
            # 先移除多余的空格，再加入其他空格
            for i in range(8 - nums_songs_last_page):
                songs_list_just_name_show_list.remove("")
            songs_list_just_name_show_list.append(file_name)
            temp = len(songs_list_just_name_show_list) % 8  # 最后一页的歌曲数目
            temp_index = temp - 1
            nums_songs_last_page = temp  # 保存当前最后一页的歌曲数目
            # 加空格
            for i in range(8 - temp):
                songs_list_just_name_show_list.append("")  # 不填充文字
            msg = QMessageBox.question(self, "Congratulation!",
                                       tmp[
                                           len(tmp) - 1] + "已经被导入了播放器中，其所处位置在播放器最后，略有不便，请见谅,如果您想直接进行播放，请点击确认",
                                       QMessageBox.Yes | QMessageBox.No)
            if msg == 16384:
                global songs_play_index
                songs_play_index = temp_index
                self.pushButton_10.click()
                music.play_music()
        else:
            pass

    # 初始化槽函数
    def setup(self):
        self.checkBox_2.hide()  # 隐藏checkBox_2
        self.change_play_order()
        self.lineEdit.setPlaceholderText("您可以输入您想听的音乐名字的一部分，然后点击搜索即可")
        global songs_play_index, songs_now_length, songs_sum_length, songs_play_index, songs_play_order
        self.SongSumLength = songs_sum_length  # 音乐的总长度
        self.SongNowLength = songs_now_length  # 当前音乐处于的进度
        self.SongIndex = songs_play_index  # 程序运行中，音乐正在播放的下标
        self.label_8.setText(songs_list_just_name[songs_play_index])
        self.list_show()
        self.timer = QTimer(self)  # 计时器
        self.timer.start(100)
        # 槽函数
        self.timer.timeout.connect(self.change_horizontalSlider_slider)  # 每秒调用一次控件
        self.timer.timeout.connect(self.show_lrc)  # 每秒调用一次控件条,展示歌词
        self.verticalSlider.valueChanged['int'].connect(self.get_voice)
        self.pushButton_20.setText(".")
        self.pushButton_20.clicked["bool"].connect(self.show_the_secret)
        self.pushButton_3.clicked["bool"].connect(self.get_file)
        self.pushButton_8.clicked["bool"].connect(self.search_file)  # 按下搜索按键
        self.pushButton_7.clicked["bool"].connect(self.search_file)  # 按下搜索按键
        self.pushButton_11.clicked["bool"].connect(self.change_song_index_next)
        self.pushButton_9.clicked["bool"].connect(self.change_song_index_last)
        self.checkBox.clicked["bool"].connect(self.change_voice_at_begin)
        self.pushButton_4.clicked["bool"].connect(self.renew_play_list)  # 更新列表
        # self.checkBox_2.clicked["bool"].connect(self.change_flag_play_order)  # 改变播放的顺序
        self.pushButton_2.clicked["bool"].connect(self.stop_music)
        self.pushButton_10.clicked["bool"].connect(self.replay_music)
        self.position_music_play = pygame.mixer.music.get_pos()  # 得到音乐当前的播放位置
        # 中间可点击的按钮事件槽函数链接
        self.pushButton_12.clicked["bool"].connect(self.change_play_songs_12)  # 改变正在播放的歌曲
        self.pushButton_13.clicked["bool"].connect(self.change_play_songs_13)  # 改变正在播放的歌曲
        self.pushButton_14.clicked["bool"].connect(self.change_play_songs_14)  # 改变正在播放的歌曲
        self.pushButton_15.clicked["bool"].connect(self.change_play_songs_15)  # 改变正在播放的歌曲
        self.pushButton_16.clicked["bool"].connect(self.change_play_songs_16)  # 改变正在播放的歌曲
        self.pushButton_17.clicked["bool"].connect(self.change_play_songs_17)  # 改变正在播放的歌曲
        self.pushButton_18.clicked["bool"].connect(self.change_play_songs_18)  # 改变正在播放的歌曲
        self.pushButton_19.clicked["bool"].connect(self.change_play_songs_19)  # 改变正在播放的歌曲

    # 展示彩蛋
    def show_the_secret(self):
        QMessageBox.information(self, "欸嘿",
                                "王雨馨，我真的很喜欢她，真希望可以和她在一起一辈子。嘿嘿，你也会祝福我们的，对吗？", QMessageBox.Yes)

    # 搜索操作
    def search_file(self):
        text = self.lineEdit.text()  # 获得文本框内的文字
        songs_play_index_temp = 0
        if text == "":
            # 弹出警示窗口
            QMessageBox.warning(self, "输入错误", "您的输入似乎是空的，请重新输入", QMessageBox.Yes)
            self.lineEdit.clear()  # 清除文本框内的文字
        else:
            # 查找歌曲
            os.chdir("./")
            searched_song_succeed = ""  # 查找的歌曲名字符串
            # 查找是否存在这首歌曲
            for song_i in os.listdir(os.curdir):
                if text in song_i:
                    searched_song_succeed = song_i.split(".")[0]
                    break
            # 查找可能需要播放的音乐下标
            for i in range(len(songs_list)):
                if searched_song_succeed == songs_list_just_name[i]:
                    songs_play_index_temp = i
            if searched_song_succeed == "" or (searched_song_succeed in searched_song_default):  # 没查找到
                QMessageBox.warning(self, "default",
                                    "十分抱歉，并未查找到您所需的歌曲，可能系统自带的音乐库中不存在您需要的歌曲，我对此表示很遗憾，再次抱歉。",
                                    QMessageBox.Yes | QMessageBox.No)
            else:  # 找到了
                # tmp = 16384 表示yes,tmp = 65536表示no
                msg_box_1 = QMessageBox.question(self, "success",
                                                 '已经查找到歌曲"' + searched_song_succeed + '"。若歌曲为您所喜欢的，请点击确认进行播放；如果不满足您的要求，请点击取消。',
                                                 QMessageBox.Yes | QMessageBox.No)
                if int(msg_box_1) == 16384:
                    self.lineEdit.clear()  # 清除文本框内的文字
                    searched_song_default.clear()  # 清除不喜欢的列表内容，防止下一次出现错误
                    global songs_play_index
                    songs_play_index = songs_play_index_temp  # 改变下标
                    music.play_music()  # 播放音乐
                    self.label_8.setText(songs_list_just_name[songs_play_index])
                else:
                    searched_song_default.append(searched_song_succeed)
                    self.lineEdit.clear()  # 清除文本框内的文字

    # 歌词展示
    def show_lrc(self):
        self.time = int(pygame.mixer.music.get_pos() / 1000 + 0.5)  # 四舍五入
        if music_lrc_dict.keys():
            if self.time in music_lrc_dict.keys():
                self.label_10.setText(music_lrc_dict[self.time])  # 展示新的歌词
                time.sleep(0.2)
        else:
            self.label_10.setText("当前歌曲在程序资源文件内不存在txt歌词文件")
        self.timer.start(100)

    # 改变播放的顺序
    def change_play_order(self):
        global songs_play_order, songs_play_index
        if songs_play_order == 1:  # 列表循环
            pygame.mixer.init()  # 初始化
            if songs_play_index <= len(songs_list) - 1:
                pygame.mixer.music.load(songs_list[songs_play_index])  # 加载音乐
                pygame.mixer.music.play(1)  # 播放
                if pygame.mixer.music.get_busy():
                    pygame.mixer.music.set_endevent(0)
                else:
                    pygame.mixer.music.set_endevent(1)
                if pygame.mixer.music.get_endevent() and songs_play_order == 1:
                    songs_play_index += 1  # 递归
                    self.change_play_order()  # 递归调用
            else:
                songs_play_index = 0  # 回到初始
        else:
            music.play_music()  # 循环播放（单曲循环）

    def change_flag_play_order(self):
        global songs_play_order
        if self.checkBox_2.checkState():  # 列表循环
            songs_play_order = 1
        else:
            songs_play_order = -1
        self.change_play_order()  # 调用函数播放器

    # 改变正在播放的歌曲
    def change_play_songs_12(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_12.text() != "":
            songs_play_index = songs_play_list_index
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_13(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_13.text() != "":
            songs_play_index = songs_play_list_index + 1
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_14(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_12.text() != "":
            songs_play_index = songs_play_list_index + 2
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_15(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_12.text() != "":
            songs_play_index = songs_play_list_index + 3
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_16(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_16.text() != "":
            songs_play_index = songs_play_list_index + 4
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_17(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_17.text() != "":
            songs_play_index = songs_play_list_index + 5
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_18(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_18.text() != "":
            songs_play_index = songs_play_list_index + 6
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 改变正在播放的歌曲
    def change_play_songs_19(self):
        global songs_play_list_index, songs_play_index
        if self.pushButton_19.text() != "":
            songs_play_index = songs_play_list_index + 7
            self.pushButton_10.click()
            self.label_8.setText(songs_list_just_name[songs_play_index])  # 展示歌曲名
            music.play_music()
        else:
            pygame.mixer.music.stop()
            QMessageBox.question(self, "Not Found", "您点击的列表不存在歌曲", QMessageBox.Yes)

    # 控制读条
    def change_horizontalSlider_slider(self):
        #  pygame.mixer.music.get_pos() 获得的是毫秒数
        global flag_exe_begin
        if flag_exe_begin:
            self.time = pygame.mixer.music.get_pos() / 1000
            percent = self.time / songs_sum_length  # 音乐当前播放的长度占总长的比例
            horizontal_slider_length = self.horizontalSlider.maximum()
            self.horizontalSlider.setSliderPosition(int(percent * horizontal_slider_length + 0.5))
        else:
            pass
        self.timer.start(100)

    # 手动控制静音和有声音，默认是静音
    def change_voice_at_begin(self):
        global flag_exe_begin
        flag_exe_begin = 1
        global exchange_quiet_to_noisy
        if exchange_quiet_to_noisy:
            music.set_sound(0)  # 静音
            self.verticalSlider.setSliderPosition(0)
            exchange_quiet_to_noisy = 0
        else:
            music.set_sound(0.5)  # 有声音
            music.play_music()  # 重启
            self.verticalSlider.setSliderPosition(int(0.5 * 100))
            exchange_quiet_to_noisy = 1

    # 停止音乐
    def stop_music(self):
        music.stop_play()

    def get_music_position(self):
        position = pygame.mixer.music.get_pos()
        return position

    # 重启音乐
    def replay_music(self):
        global flag_exe_begin
        flag_exe_begin = 1
        music.set_sound(0.5)
        music.play_music()
        # 改变小喇叭的图标
        self.pushButton_23.setVisible(1)
        self.label.setVisible(0)
        # 程序启动时，改变check框
        if self.checkBox.checkState() == False:
            self.checkBox.click()

    # 获得音量
    def get_voice(self, voice):
        global voice_level_move, flag_voice_level_changed
        voice_level_move = voice / 100
        if flag_voice_level_changed:
            music.pause_play()  # 暂停播放
            music.set_sound(voice_level_move)
            music.unpause_play()  # 继续播放
        else:
            flag_voice_level_changed = 1
            music.pause_play()  # 暂停播放
            music.set_sound(voice_level_move)
            music.unpause_play()  # 继续播放

    # 歌曲列表展示
    def list_show(self):
        # 显示
        self.pushButton_12.setText(songs_list_just_name_show_list[songs_play_list_index])
        self.pushButton_13.setText(songs_list_just_name_show_list[songs_play_list_index + 1])
        self.pushButton_14.setText(songs_list_just_name_show_list[songs_play_list_index + 2])
        self.pushButton_15.setText(songs_list_just_name_show_list[songs_play_list_index + 3])
        self.pushButton_16.setText(songs_list_just_name_show_list[songs_play_list_index + 4])
        self.pushButton_17.setText(songs_list_just_name_show_list[songs_play_list_index + 5])
        self.pushButton_18.setText(songs_list_just_name_show_list[songs_play_list_index + 6])
        self.pushButton_19.setText(songs_list_just_name_show_list[songs_play_list_index + 7])

    # 更新播放列表
    def renew_play_list(self):
        global songs_play_list_index
        if songs_play_list_index == len(songs_list_just_name_show_list) - 8:
            songs_play_list_index = 0  # 到达末端，列表归零
        else:
            songs_play_list_index += 8  # 加载下一页
        self.list_show()

    # 播放下一首歌曲
    def change_song_index_next(self):
        global flag_exe_begin
        flag_exe_begin = 1
        # 处理歌曲是否溢出列表
        if self.SongIndex <= len(songs_list_just_name) - 1:
            self.SongIndex += 1
            global songs_play_index
            songs_play_index = self.SongIndex
            music.play_music()
            self.label_8.setText(songs_list_just_name[songs_play_index])
            self.pushButton_10.clicked.connect(self.change_begin_voice)
        else:
            music.play_music()

    def change_begin_voice(self):
        global voice_level_begin
        voice_level_begin = 0.5

    # 播放上一首歌曲
    def change_song_index_last(self):
        global flag_exe_begin
        flag_exe_begin = 1
        # 处理歌曲是否溢出列表
        if self.SongIndex:
            self.SongIndex -= 1
            global songs_play_index
            songs_play_index = self.SongIndex
            music.play_music()
            self.label_8.setText(songs_list_just_name[songs_play_index])
        else:
            music.play_music()


# 音乐类
class Music:
    def __init__(self):
        self.play_music()

    # 设置音量
    def set_sound(self, level):
        pygame.mixer.music.set_volume(level)

    # 暂停播放
    def pause_play(self):
        pygame.mixer.music.pause()

    # 继续播放
    def unpause_play(self):
        pygame.mixer.music.unpause()

    # 停止播放
    def stop_play(self):
        pygame.mixer.music.stop()

    # 读取歌词文件，并将其添加到字典以及列表中
    def add_lrc_dir(self, song_name):
        global music_lrc_list, music_lrc_dict
        music_lrc_dict.clear()  # 清空字典
        music_lrc_list.clear()  # 清空列表
        music_lrc_dict_temp = {}  # 临时的字典
        song_temp = song_name.split(".")[0] + ".txt"
        try:
            file = open(song_temp, "r", encoding="utf-8")
            for i in file.readlines():
                lrc_word = i.replace("[", "]").strip().split("]")
                for j in range(len(lrc_word) - 1):
                    if lrc_word[j]:
                        music_lrc_dict_temp[lrc_word[j]] = lrc_word[-1]
            # 歌词列表
            for key in sorted(music_lrc_dict_temp):
                temp_list = []
                temp_str = key.split(":")
                # 转换成秒
                time = int(float(temp_str[0]) * 60 + float(temp_str[1].split(".")[0]) + float(
                    temp_str[1].split(".")[1]) / 100 + 0.5)  # 四舍五入
                temp_list.append(time)
                temp_list.append(str(music_lrc_dict_temp[key]))
                music_lrc_list.append(temp_list)
                music_lrc_dict[time] = music_lrc_dict_temp[key]
            file.close()
        except FileNotFoundError:  # 不存在这个文件
            music_lrc_list.clear()
            music_lrc_dict.clear()

    # 播放音乐
    def play_music(self):
        global songs_sum_length, flag_voice_level_changed, position_music_play, songs_play_order
        global songs_play_index, flag_exe_begin
        extern_name = songs_list[songs_play_index].split(".")[1]  # 获得扩展名
        # 加载歌词文件
        self.add_lrc_dir(songs_list[songs_play_index])
        # 区分音乐格式, 分别获取歌曲长度
        # MP3
        if extern_name == "mp3":
            songs_sum_length = MP3(songs_list[songs_play_index]).info.length  # 歌曲长度
        # ogg
        if extern_name == "ogg":
            tmp1 = OggVorbis(songs_list[songs_play_index])
            songs_sum_length = float(tmp1.info.pprint().split(" ")[2])  # 歌曲长度
        # flac
        if extern_name == "flac":
            tmp2 = FLAC(songs_list[songs_play_index]).info.pprint()
            songs_sum_length = float(tmp2.split(" ")[1])  # 歌曲长度
        pygame.mixer.init()  # 初始化歌曲
        pygame.mixer.music.load(songs_list[songs_play_index])  # 加载音乐
        if flag_voice_level_changed:
            pygame.mixer.music.set_volume(voice_level_move)
        else:
            pygame.mixer.music.set_volume(voice_level_begin)
        pygame.mixer.music.set_volume(voice_level_move)
        if flag_exe_begin == 0:
            self.stop_play()  # 程序刚开始需要暂停播放
        else:
            pygame.mixer.music.play(-1, 0, 0)  # 单曲循环播放


# 查找音乐,并填充列表
def add_songs_list(path):
    global nums_songs_last_page
    extend_songs_name = [".mp3", ".ogg", ".wma", ".flac"]
    os.chdir(path)  # 文件列表
    for songs_i in os.listdir(os.curdir):
        music_prop = os.path.splitext(songs_i)
        if music_prop[1] in extend_songs_name:
            songs_list.append(songs_i)
            temp = songs_i.split(".")[0]
            songs_list_just_name.append(temp)
            songs_list_just_name_show_list.append(temp)
    temp = len(songs_list_just_name_show_list) % 8  # 最后一页剩下的需要填充的空格数目
    nums_songs_last_page = temp
    for i in range(8 - temp):
        songs_list_just_name_show_list.append("")  # 不填充文字
    file = open("SongsList.txt", "a", encoding="utf=8")  # 写入文件
    for name in songs_list:
        file.write(name + "\n")
    file.close()


# 查找txt歌词文件，并将其添加到列表中
def add_lrc_list(path):
    os.chdir(path)  # 文件列表
    for lrc in os.listdir(os.curdir):
        lrc_prop = os.path.splitext(lrc)
        if lrc_prop[1] == ".txt":
            temp = lrc.split(".")[0]
            lrc_list.append(temp)
            lrc_list.append(temp)


# 展示界面以及播放音乐
def play_music():
    global help_window
    global music, ui
    dir_songs_system = "./songs/system_built"  # 音乐路径
    add_songs_list(dir_songs_system)  # 查找并初始化音乐列表
    add_lrc_list("./")  # lrc歌词文件初始化(文件指针指向"./songs/system_built"，需要改变相对路径)
    music = Music()  # 初始化播放器
    ui = MainUIAndSlot(main_windows)  # 实例化界面对象
    main_windows.setWindowTitle("Music Player")
    main_windows.show()
    window.exec_()


if __name__ == "__main__":
    play_music()
